#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <openssl/ssl.h>
#include <openssl/err.h>
#include <pthread.h>
#include <time.h>

// 全局配置
#define BUFFER_SIZE 8192
#define MAX_USERNAME_LEN 64
#define MAX_PASSWORD_LEN 64
#define MAX_COMMAND_LEN 256

// 客户端版本
#define SSLVPN_CLIENT_VERSION "1.0.0"

// 连接状态枚举
typedef enum {
    CLIENT_STATE_DISCONNECTED,
    CLIENT_STATE_CONNECTING,
    CLIENT_STATE_AUTHENTICATING,
    CLIENT_STATE_AUTHENTICATED,
    CLIENT_STATE_ESTABLISHED,
    CLIENT_STATE_CLOSING
} client_state_t;

// SSL VPN客户端结构
typedef struct {
    int sockfd;
    SSL* ssl;
    SSL_CTX* ssl_ctx;
    client_state_t state;
    char server_ip[16];
    int server_port;
    char username[MAX_USERNAME_LEN];
    char password[MAX_PASSWORD_LEN];
    int session_id;
    char tunnel_ip[16];
    int mode; // 0: 代理模式, 1: 隧道模式
    int running;
} sslvpn_client_t;

// 全局客户端实例
sslvpn_client_t client;

// 初始化SSL库
void init_ssl() {
    SSL_load_error_strings();
    OpenSSL_add_ssl_algorithms();
}

// 清理SSL库
void cleanup_ssl() {
    EVP_cleanup();
}

// 创建SSL上下文
SSL_CTX* create_ssl_context() {
    const SSL_METHOD* method;
    SSL_CTX* ctx;

    method = TLS_client_method();
    ctx = SSL_CTX_new(method);
    if (!ctx) {
        perror("无法创建SSL上下文");
        ERR_print_errors_fp(stderr);
        exit(EXIT_FAILURE);
    }

    // 设置验证模式（实际应用中应根据需求调整）
    SSL_CTX_set_verify(ctx, SSL_VERIFY_NONE, NULL);

    return ctx;
}

// 创建TCP连接
int create_tcp_connection(const char* server_ip, int server_port) {
    int sockfd;
    struct sockaddr_in addr;

    sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd < 0) {
        perror("无法创建套接字");
        return -1;
    }

    memset(&addr, 0, sizeof(addr));
    addr.sin_family = AF_INET;
    addr.sin_port = htons(server_port);
    if (inet_pton(AF_INET, server_ip, &addr.sin_addr) <= 0) {
        perror("无效的服务器地址");
        close(sockfd);
        return -1;
    }

    if (connect(sockfd, (struct sockaddr*)&addr, sizeof(addr)) < 0) {
        perror("连接服务器失败");
        close(sockfd);
        return -1;
    }

    return sockfd;
}

// 初始化客户端
void init_client(const char* server_ip, int server_port, const char* username, const char* password, int mode) {
    memset(&client, 0, sizeof(sslvpn_client_t));
    
    strcpy(client.server_ip, server_ip);
    client.server_port = server_port;
    strcpy(client.username, username);
    strcpy(client.password, password);
    client.mode = mode;
    client.running = 1;
    
    // 初始化SSL
    init_ssl();
    
    // 创建SSL上下文
    client.ssl_ctx = create_ssl_context();
    
    printf("SSL VPN客户端 v%s 初始化成功\n", SSLVPN_CLIENT_VERSION);
    printf("服务器: %s:%d\n", server_ip, server_port);
    printf("模式: %s\n", mode == 0 ? "代理模式" : "隧道模式");
}

// 清理客户端资源
void cleanup_client() {
    // 关闭SSL连接
    if (client.ssl) {
        SSL_shutdown(client.ssl);
        SSL_free(client.ssl);
    }
    
    // 关闭套接字
    if (client.sockfd > 0) {
        close(client.sockfd);
    }
    
    // 释放SSL上下文
    if (client.ssl_ctx) {
        SSL_CTX_free(client.ssl_ctx);
    }
    
    // 清理SSL库
    cleanup_ssl();
    
    printf("SSL VPN客户端已关闭\n");
}

// 连接到SSL VPN服务器
int connect_to_server() {
    client.state = CLIENT_STATE_CONNECTING;
    
    // 创建TCP连接
    client.sockfd = create_tcp_connection(client.server_ip, client.server_port);
    if (client.sockfd < 0) {
        client.state = CLIENT_STATE_DISCONNECTED;
        return 0;
    }
    
    // 创建SSL连接
    client.ssl = SSL_new(client.ssl_ctx);
    if (!client.ssl) {
        perror("无法创建SSL连接");
        ERR_print_errors_fp(stderr);
        close(client.sockfd);
        client.sockfd = 0;
        client.state = CLIENT_STATE_DISCONNECTED;
        return 0;
    }
    
    // 绑定套接字
    SSL_set_fd(client.ssl, client.sockfd);
    
    // 进行SSL握手
    if (SSL_connect(client.ssl) <= 0) {
        perror("SSL握手失败");
        ERR_print_errors_fp(stderr);
        SSL_free(client.ssl);
        close(client.sockfd);
        client.ssl = NULL;
        client.sockfd = 0;
        client.state = CLIENT_STATE_DISCONNECTED;
        return 0;
    }
    
    printf("已成功连接到SSL VPN服务器\n");
    client.state = CLIENT_STATE_AUTHENTICATING;
    
    return 1;
}

// 发送认证请求
int send_authentication() {
    char buffer[BUFFER_SIZE];
    int bytes_written, bytes_read;
    
    // 构造认证请求
    sprintf(buffer, "AUTH %s %s", client.username, client.password);
    
    // 发送认证请求
    bytes_written = SSL_write(client.ssl, buffer, strlen(buffer));
    if (bytes_written <= 0) {
        perror("发送认证请求失败");
        return 0;
    }
    
    // 接收认证响应
    bytes_read = SSL_read(client.ssl, buffer, BUFFER_SIZE - 1);
    if (bytes_read <= 0) {
        perror("接收认证响应失败");
        return 0;
    }
    
    buffer[bytes_read] = '\0';
    
    // 解析认证响应
    if (strstr(buffer, "AUTH_OK") != NULL) {
        // 认证成功
        int session_id;
        char tunnel_ip[16];
        
        if (sscanf(buffer, "AUTH_OK %d %s", &session_id, tunnel_ip) == 2) {
            client.session_id = session_id;
            strcpy(client.tunnel_ip, tunnel_ip);
            client.state = CLIENT_STATE_AUTHENTICATED;
            
            printf("认证成功！会话ID: %d，隧道IP: %s\n", session_id, tunnel_ip);
            return 1;
        }
    } else if (strstr(buffer, "AUTH_FAIL") != NULL) {
        // 认证失败
        printf("认证失败：用户名或密码错误\n");
        return 0;
    }
    
    // 未知响应
    printf("接收到未知的认证响应: %s\n", buffer);
    return 0;
}

// 在代理模式下发送HTTP请求
void send_proxy_request(const char* path) {
    char buffer[BUFFER_SIZE];
    int bytes_written, bytes_read;
    
    if (client.state != CLIENT_STATE_AUTHENTICATED && client.state != CLIENT_STATE_ESTABLISHED) {
        printf("错误：未认证或连接已断开\n");
        return;
    }
    
    // 构造HTTP请求
    sprintf(buffer, "GET %s HTTP/1.1\r\nHost: %s\r\nConnection: close\r\n\r\n", path, client.server_ip);
    
    // 发送请求
    bytes_written = SSL_write(client.ssl, buffer, strlen(buffer));
    if (bytes_written <= 0) {
        perror("发送HTTP请求失败");
        return;
    }
    
    printf("已发送HTTP请求，正在等待响应...\n");
    
    // 接收响应
    while ((bytes_read = SSL_read(client.ssl, buffer, BUFFER_SIZE - 1)) > 0) {
        buffer[bytes_read] = '\0';
        printf("%s", buffer);
    }
    
    if (bytes_read < 0) {
        perror("接收HTTP响应失败");
    }
}

// 在隧道模式下发送数据
void send_tunnel_data(const void* data, int data_len) {
    int bytes_written;
    
    if (client.state != CLIENT_STATE_AUTHENTICATED && client.state != CLIENT_STATE_ESTABLISHED) {
        printf("错误：未认证或连接已断开\n");
        return;
    }
    
    // 发送隧道数据
    bytes_written = SSL_write(client.ssl, data, data_len);
    if (bytes_written <= 0) {
        perror("发送隧道数据失败");
        return;
    }
    
    printf("已发送隧道数据，长度: %d 字节\n", bytes_written);
}

// 数据包封装函数（用于隧道模式）
int packet_encapsulate(const void* packet, int packet_len, void** encapsulated_data, int* encapsulated_len) {
    // 为封装数据分配内存
    *encapsulated_len = packet_len + sizeof(int) + 8; // 添加长度字段和头部
    *encapsulated_data = (void*)malloc(*encapsulated_len);
    if (!*encapsulated_data) {
        return 0;
    }
    
    // 添加封装头部
    memset(*encapsulated_data, 0, *encapsulated_len);
    memcpy(*encapsulated_data, "SSLVPN", 6); // 隧道标识
    
    // 添加长度字段
    int* len_ptr = (int*)((*encapsulated_data) + 6);
    *len_ptr = htonl(packet_len);
    
    // 复制原始数据包
    memcpy(*encapsulated_data + 10, packet, packet_len);
    
    return 1;
}

// 数据包解封装函数（用于隧道模式）
int packet_decapsulate(const void* encapsulated_data, int encapsulated_len, void** packet, int* packet_len) {
    // 检查数据长度
    if (encapsulated_len < 10) {
        return 0;
    }
    
    // 检查隧道标识
    if (memcmp(encapsulated_data, "SSLVPN", 6) != 0) {
        return 0;
    }
    
    // 获取原始数据包长度
    int* len_ptr = (int*)((const char*)encapsulated_data + 6);
    *packet_len = ntohl(*len_ptr);
    
    // 检查长度是否合法
    if (*packet_len <= 0 || *packet_len > encapsulated_len - 10) {
        return 0;
    }
    
    // 分配内存并复制原始数据包
    *packet = (void*)malloc(*packet_len);
    if (!*packet) {
        return 0;
    }
    
    memcpy(*packet, (const char*)encapsulated_data + 10, *packet_len);
    
    return 1;
}

// 创建虚拟网卡（示例函数，实际实现需要根据操作系统进行）
int create_virtual_network_interface(const char* interface_name, const char* ip_address, const char* netmask) {
    // 实际应用中，这里应该调用操作系统API创建虚拟网卡
    // 不同操作系统的实现方式不同
    
    // 这里仅作为示例，返回成功
    printf("创建虚拟网卡 %s，IP地址: %s，子网掩码: %s\n", interface_name, ip_address, netmask);
    return 1;
}

// 接收服务器消息的线程函数
void* receive_messages(void* arg) {
    char buffer[BUFFER_SIZE];
    int bytes_read;
    
    while (client.running) {
        if (client.state == CLIENT_STATE_AUTHENTICATED || client.state == CLIENT_STATE_ESTABLISHED) {
            bytes_read = SSL_read(client.ssl, buffer, BUFFER_SIZE - 1);
            if (bytes_read > 0) {
                buffer[bytes_read] = '\0';
                
                if (client.mode == 0) {
                    // 代理模式：直接显示响应
                    printf("收到服务器响应:\n%s\n", buffer);
                } else {
                    // 隧道模式：解析隧道数据
                    void* packet;
                    int packet_len;
                    if (packet_decapsulate(buffer, bytes_read, &packet, &packet_len)) {
                        printf("收到隧道数据包，长度: %d 字节\n", packet_len);
                        // 在实际应用中，应该将数据包发送到虚拟网卡
                        free(packet);
                    } else {
                        printf("无法解析隧道数据包\n");
                    }
                }
            } else if (bytes_read == 0) {
                // 连接关闭
                printf("服务器已关闭连接\n");
                client.state = CLIENT_STATE_DISCONNECTED;
                break;
            } else {
                // 发生错误
                if (client.running) { // 只有在运行状态下才报错
                    perror("接收数据失败");
                    ERR_print_errors_fp(stderr);
                }
                break;
            }
        } else {
            // 未连接状态，短暂休眠
            usleep(100000); // 100ms
        }
    }
    
    return NULL;
}

// 显示命令帮助
void show_help() {
    printf("可用命令：\n");
    printf("  connect     - 连接到SSL VPN服务器\n");
    printf("  auth        - 发送认证请求\n");
    printf("  proxy <path> - 在代理模式下发送HTTP请求\n");
    printf("  tunnel <data> - 在隧道模式下发送测试数据\n");
    printf("  status      - 显示连接状态\n");
    printf("  help        - 显示帮助信息\n");
    printf("  quit/exit   - 退出客户端\n");
}

// 显示连接状态
void show_status() {
    printf("当前状态：");
    switch (client.state) {
        case CLIENT_STATE_DISCONNECTED:
            printf("断开连接\n");
            break;
        case CLIENT_STATE_CONNECTING:
            printf("连接中...\n");
            break;
        case CLIENT_STATE_AUTHENTICATING:
            printf("认证中...\n");
            break;
        case CLIENT_STATE_AUTHENTICATED:
            printf("已认证\n");
            printf("  会话ID: %d\n", client.session_id);
            printf("  隧道IP: %s\n", client.tunnel_ip);
            break;
        case CLIENT_STATE_ESTABLISHED:
            printf("连接已建立\n");
            printf("  会话ID: %d\n", client.session_id);
            printf("  隧道IP: %s\n", client.tunnel_ip);
            break;
        case CLIENT_STATE_CLOSING:
            printf("正在关闭...\n");
            break;
        default:
            printf("未知\n");
            break;
    }
}

// 处理用户命令
void handle_commands() {
    char command[MAX_COMMAND_LEN];
    pthread_t receive_thread;
    
    // 创建接收线程
    if (pthread_create(&receive_thread, NULL, receive_messages, NULL) != 0) {
        perror("创建接收线程失败");
        return;
    }
    
    // 分离线程，自动回收资源
    pthread_detach(receive_thread);
    
    // 显示欢迎信息和帮助
    printf("\n欢迎使用SSL VPN客户端\n");
    show_help();
    
    // 命令循环
    while (client.running) {
        printf("\n> ");
        fflush(stdout);
        
        // 读取用户命令
        if (fgets(command, sizeof(command), stdin) == NULL) {
            break;
        }
        
        // 去除换行符
        command[strcspn(command, "\n")] = '\0';
        
        // 解析并执行命令
        if (strcmp(command, "connect") == 0) {
            if (connect_to_server()) {
                printf("连接命令执行成功\n");
            } else {
                printf("连接命令执行失败\n");
            }
        } else if (strcmp(command, "auth") == 0) {
            if (send_authentication()) {
                printf("认证命令执行成功\n");
                client.state = CLIENT_STATE_ESTABLISHED;
            } else {
                printf("认证命令执行失败\n");
            }
        } else if (strncmp(command, "proxy ", 6) == 0) {
            char* path = command + 6;
            send_proxy_request(path);
        } else if (strncmp(command, "tunnel ", 7) == 0) {
            char* data = command + 7;
            send_tunnel_data(data, strlen(data));
        } else if (strcmp(command, "status") == 0) {
            show_status();
        } else if (strcmp(command, "help") == 0) {
            show_help();
        } else if (strcmp(command, "quit") == 0 || strcmp(command, "exit") == 0) {
            printf("正在退出客户端...\n");
            client.running = 0;
            break;
        } else if (strlen(command) > 0) {
            printf("未知命令：%s\n", command);
            show_help();
        }
    }
}

// 主函数
int main(int argc, char* argv[]) {
    const char* server_ip = "127.0.0.1";
    int server_port = 443;
    const char* username = "admin";
    const char* password = "admin123";
    int mode = 0; // 默认代理模式
    
    // 解析命令行参数
    for (int i = 1; i < argc; i++) {
        if (strcmp(argv[i], "-s") == 0 && i + 1 < argc) {
            server_ip = argv[i + 1];
            i++;
        } else if (strcmp(argv[i], "-p") == 0 && i + 1 < argc) {
            server_port = atoi(argv[i + 1]);
            i++;
        } else if (strcmp(argv[i], "-u") == 0 && i + 1 < argc) {
            username = argv[i + 1];
            i++;
        } else if (strcmp(argv[i], "-pw") == 0 && i + 1 < argc) {
            password = argv[i + 1];
            i++;
        } else if (strcmp(argv[i], "-m") == 0 && i + 1 < argc) {
            mode = atoi(argv[i + 1]);
            if (mode != 0 && mode != 1) {
                printf("模式参数无效，使用默认模式（0: 代理模式）\n");
                mode = 0;
            }
            i++;
        } else if (strcmp(argv[i], "-h") == 0 || strcmp(argv[i], "--help") == 0) {
            printf("用法: %s [-s 服务器IP] [-p 端口] [-u 用户名] [-pw 密码] [-m 模式(0:代理,1:隧道)] [-h]\n", argv[0]);
            return 0;
        }
    }
    
    // 初始化客户端
    init_client(server_ip, server_port, username, password, mode);
    
    // 处理用户命令
    handle_commands();
    
    // 清理资源
    cleanup_client();
    
    return 0;
}